package com.cookman.controllers;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.assets.AssetManager;
import com.cookman.Pandemic;
import com.cookman.actions.*;
import com.cookman.assets.AssetsImpl;
import com.cookman.assets.AssetsLocator;
import com.cookman.cards.CityCard;
import com.cookman.factories.CitiesFactory;
import com.cookman.gameobjects.CityActor;
import com.cookman.gameobjects.CityCardActor;
import com.cookman.interfaces.IGameController;
import com.cookman.interfaces.IGameListener;
import com.cookman.interfaces.INotifyEvent;
import com.cookman.interfaces.IUIController;
import com.cookman.ioc.ApplicationFactory;
import com.cookman.notifications.*;
import com.cookman.renderers.WorldRenderer;
import com.cookman.screens.GameScreen;
import com.cookman.serviceLocators.ServiceLocator;
import com.cookman.utils.UiUtils;
import com.cookman.world.entities.City;
import com.cookman.world.entities.Disease;
import com.cookman.world.entities.Player;
import com.cookman.world.entities.Stats;
import com.cookman.world.repository.CitiesRepositoryImpl;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;

public class AliceUI implements IGameListener, IUIController {

    private Pandemic pandemic;
    private IGameController gameController;
    private int turnCounterAll = 0;
    private int turnCounter = 0;
    private Action lastSelectedAction;
    private Player currentPlayer;
    private List<Action> lastActions;
    private INotifyEvent lastEvent;

    public void create(GameAlice gameAlice, List<Player> players) {
        try {
            //init all assets first
            AssetsImpl.instance.init(new AssetManager());
            AssetsLocator.provideAssets(AssetsImpl.instance);
            //init Pandemic  will initialize game core from XML configuration files
            pandemic = new Pandemic();
            pandemic.initGame(this, players);
            //Create cities for ui based on cities City class from core
            CitiesFactory.loadCities(ApplicationFactory.getCitiesRepository().getCities());
            //Create new game screen ana set it as current screen
            GameScreen gameScreen = new GameScreen(gameAlice);
            gameAlice.setScreen(gameScreen);
            //Create world renderer
            ServiceLocator.setWorldRenderer(new WorldRenderer());

//            List<CityCard> cards = ApplicationFactory.getCitiesCardFactory().getCardsByColor(Disease.BLACK);
//            players.get(0).getCards().addAll(cards);

                       /*for(Card card:cards){
                if(card.getName().equals("Atlanta")){
                    players.get(0).addCard(card);
                    break;
                }
            }*/
           /* City city=ApplicationFactory.getCitiesRepository().getCityByName("Atlanta");
            city.getDiseases().add(ApplicationFactory.getDiseaseRepository().getBlackDisease());
            city.getDiseases().add(ApplicationFactory.getDiseaseRepository().getBlackDisease());
            city.getDiseases().add(ApplicationFactory.getDiseaseRepository().getBlackDisease());
            city.getDiseases().add(ApplicationFactory.getDiseaseRepository().getBlueDisease());
            city.getDiseases().add(ApplicationFactory.getDiseaseRepository().getBlueDisease());
            city.getDiseases().add(ApplicationFactory.getDiseaseRepository().getBlueDisease());
            city.getDiseases().add(ApplicationFactory.getDiseaseRepository().getYellowDisease());
            city.getDiseases().add(ApplicationFactory.getDiseaseRepository().getYellowDisease());
            city.getDiseases().add(ApplicationFactory.getDiseaseRepository().getYellowDisease());
            city.getDiseases().add(ApplicationFactory.getDiseaseRepository().getRedDisease());
            city.getDiseases().add(ApplicationFactory.getDiseaseRepository().getRedDisease());
            city.getDiseases().add(ApplicationFactory.getDiseaseRepository().getRedDisease());*/





            //Start pandemic core so it will call updateStatus() and initiateNextPlayerTurn() on IUIController
            pandemic.startGame();
        } catch (Exception e) {
            Gdx.app.log("Alice", e.toString());
        }
    }

    @Override
    public void setGameController(IGameController iGameController) {
        this.gameController = iGameController;
    }

    /**
     * notify method is called by GameController when user selects action
     *
     * @param event
     */
    @Override
    public void notify(INotifyEvent event) {
        lastEvent = event;
        if (event instanceof SelectCityNotification) {
            selectCity((SelectCityNotification) event);
        } else if (event instanceof CityInfectedNotification) {

        } else if (event instanceof SelectCityCardNotification) {
            selectCityCard((SelectCityCardNotification) event);
        } else if (event instanceof SelectActionNotification) {
            selectAction((SelectActionNotification) event);
        } else if (event instanceof SelectDiseaseNotification) {
            selectCityDisease((SelectDiseaseNotification) event);
        } else if (event instanceof SelectPlayerNotification) {
            selectPlayer((SelectPlayerNotification) event);
        } else if (event instanceof SelectCityCardForCureNotification) {
            selectCityCardsForCure((SelectCityCardForCureNotification) event);
        } else if (event instanceof GameEndNotification) {
            notifyGameEnd((GameEndNotification) event);
        }
    }

    public void notifyGameEnd(GameEndNotification event) {
        System.out.println("GAME OVER");
        String stats = event.isValue() ? "Win" : "Loss";
        System.out.println("with status:" + stats);
        //System.exit(0);
    }

    private void selectPlayer(SelectPlayerNotification event) {
        System.out.println("Available players:");
        int i = 0;
        for (Player player : event.getPlayers()) {
            System.out.println(i + ". " + player.getName());
            i += 1;
        }
        selectPlayer(event.getPlayers());
    }

    protected void selectPlayer(List<Player> players) {
        ServiceLocator.getWorldRenderer().setPlayers(players);
        ServiceLocator.getWorldRenderer().showPlayerDeck(true);
    }

    @Override
    public void selectPlayer(Player player) {
        lastSelectedAction.setSecondPlayer(player);
    }

    private void selectCityCard(SelectCityCardNotification event) {
        addAcceptCancelButtons();
        System.out.println("Available cities:");
        int i = 0;
        List<String> activeId = new ArrayList<>();
        for (CityCard card : event.getAvailableCards()) {
            System.out.println(i + ". " + card.getCity().getName());
            activeId.add(card.getCity().getId());
            i += 1;
        }
        ServiceLocator.getWorldRenderer().showCardDeck(true);
        setActiveCities(Collections.EMPTY_LIST);
    }

    @Override
    public void selectCityCard(CityCardActor cityCardActor) {
        lastSelectedAction.setCard(cityCardActor.getCard());
    }

    @Override
    public void selectDisease(Disease disease) {
        lastSelectedAction.setDisease(disease);
    }

    private void selectCityDisease(SelectDiseaseNotification event) {
        UiUtils.printDiseaseStats(event.getDiseases());
        ServiceLocator.getWorldRenderer().showDiseaseDeck(true);
    }

    public void selectAction(SelectActionNotification event) {
        //  gameScreen.setPlayerActions(event.getActions());
    }

    private void selectCity(SelectCityNotification event) {
        addAcceptCancelButtons();
        System.out.println("Available cities:");
        int i = 0;
        List<String> activeId = new ArrayList<>();
        for (City city : event.getAvailableCities()) {
            System.out.println(i + ". " + city.getName());
            activeId.add(city.getId());
            i += 1;
        }
        setActiveCities(activeId);
    }

    private void setActiveCities(List<String> activeId) {
        List<CityActor> cityActors = CitiesFactory.getCities();
        for (CityActor cityActor : cityActors) {
            cityActor.setIsActive(activeId.indexOf(cityActor.getId()) > -1);
        }
    }

    private void selectCityCardsForCure(SelectCityCardForCureNotification event) {
        System.out.println("Available city cards:");
        int i = 0;
        for (CityCard card : event.getCards()) {
            System.out.println(i + ". " + card.getCity().getName());
            i += 1;
        }
        selectCitiesCards(event.getCards(), event.getCount());
    }

    protected void selectCitiesCards(List<CityCard> cards, int count) {
        updateCardPanel(cards, true, count);
        ServiceLocator.getWorldRenderer().showCardDeck(true);
    }

    @Override
    public void selectCitiesCards(List<CityCard> cards) {
        if (lastSelectedAction instanceof InventCureAction && lastEvent instanceof SelectCityCardForCureNotification) {
            int count = ((SelectCityCardForCureNotification) lastEvent).getCount();
            if (cards.size() == count) {
                ((InventCureAction) lastSelectedAction).setCityCardList(cards);
            }
        }
    }

    private void resetActiveCities() {
        List<CityActor> cityActors = CitiesFactory.getCities();
        for (CityActor cityActor : cityActors) {
            cityActor.setIsActive(true);
            cityActor.setIsSelected(false);
        }
    }

    public void resetSelectedCities() {
        List<CityActor> cityActors = CitiesFactory.getCities();
        for (CityActor cityActor : cityActors) {
            cityActor.setIsSelected(false);
        }
    }

    private void setPlayersInCity(List<Player> players) {
        HashMap<String, List<Player>> playerCityMap = new HashMap<>();
        for (Player player : players) {
            String cityId = player.getCity().getId();
            List<Player> playersInCity = playerCityMap.get(cityId);
            if (playersInCity == null) {
                playersInCity = new ArrayList<>();
                playerCityMap.put(cityId, playersInCity);
            }
            playersInCity.add(player);
        }

        if (CitiesFactory.getCities() != null) {
            List<CityActor> cityActors = CitiesFactory.getCities();

            for (CityActor cityActor : cityActors) {
                String cityId = cityActor.getCity().getId();
                if (playerCityMap.containsKey(cityId)) {
                    cityActor.setPlayers(playerCityMap.get(cityId));
                } else {
                    cityActor.setPlayers(Collections.EMPTY_LIST);
                }
            }
        }
    }

    @Override
    public void updateStatus(Stats stats) {
        UiUtils.printPlayerStats(stats);
        ServiceLocator.getWorldRenderer().setDiseaseDistribution(stats.getDistribution()+1);
        currentPlayer = stats.getCurrentPlayer();
        setPlayersInCity(stats.getPlayers());
    }

    protected Boolean lastActionAccepted = false;
    protected Boolean firstActionExecution = true;

    public boolean executeAction(Action action) {

        if (action instanceof CancelAction) {
            return doCancelAction();
        }

        if (!(action instanceof AcceptAction)) {
            lastSelectedAction = action;
        } else {
            lastActionAccepted = true;
        }

        if ((!firstActionExecution) && !lastActionAccepted) return false;

        if (showAcceptDialogForSpecialActions(action)) return false;


        boolean result = gameController.executeAction(lastSelectedAction);
        firstActionExecution = false;

        if (result) {
            System.out.println(UiUtils.actionLabelFunction(lastSelectedAction) + " executed" + turnCounter + "[" + turnCounterAll + "]");
            firstActionExecution = true;
            lastSelectedAction = null;
            lastActions = null;
            lastActionAccepted = false;
            turnCounterAll += 1;
            turnCounter += 1;
            resetActiveCities();
            gameController.requestNextActionForCurrentPlayerTurn();
        } else {
            System.out.println(action.getId() + " failed to execute");
        }
        return result;
    }

    private boolean showAcceptDialogForSpecialActions(Action action) {
        if ((action instanceof BuildLabAsEngineerAction) && !lastActionAccepted) {
            addAcceptCancelButtons();
            return true;
        }

        if (action instanceof TakeCardFromPlayerAction && !lastActionAccepted) {
            ((TakeCardFromPlayerAction) action).findAndSetSecondPlayer(currentPlayer);
            addAcceptCancelButtons();
            return true;
        }
        return false;
    }

    private Boolean doCancelAction() {
        System.out.println(UiUtils.actionLabelFunction(lastSelectedAction) + " canceled" + turnCounter);
        firstActionExecution = true;
        lastActionAccepted = false;
        resetActiveCities();
        lastSelectedAction.reset();
        lastSelectedAction = null;
        updateActionPanel(lastActions);
        updateCardPanel(currentPlayer.getCityCards());
        updateDiseasePanel(currentPlayer.getCity().getDiseases());
        updatePlayerPanel(new ArrayList<Player>());
        return false;
    }

    public void selectCity(CityActor cityActor) {
        if (lastSelectedAction != null) {
            System.out.println("Select city");
            City city = cityActor.getCity();
            System.out.println("Selected city:" + city.getName());
            lastSelectedAction.setCity(city);
            executeAction(lastSelectedAction);
        }
    }

    private CityCard getCityCardByCity(City city, List<CityCard> cards) {
        for (CityCard card : cards) {
            if (card.getCity().equals(city))
                return card;
        }
        return null;
    }

    @Override
    public void initiateNextPlayerTurn(Player player, List<Action> actions) {

        if (currentPlayer != player) {
            turnCounter = 0;

        }

       /* List<CityActor> cityActors = CitiesFactory.getCities();
        for (CityActor cityActor : cityActors) {
            if(currentPlayer.getCity().getId().equals(cityActor.getId())){
               // WorldRenderer.camera.position.set(0, 0, 0);
               // WorldRenderer.camera.update();
                //WorldRenderer.camera.translate(cityActor.getX()*WorldRenderer.camera.zoom,cityActor.getY()*WorldRenderer.camera.zoom);
                WorldRenderer.camera.position.set(cityActor.getX()*WorldRenderer.camera.zoom,cityActor.getY()*WorldRenderer.camera.zoom, 0);
                System.out.println("CAMERA:"+cityActor.getX()*WorldRenderer.camera.zoom+":"+cityActor.getY()*WorldRenderer.camera.zoom);


                float effectiveViewportWidth = WorldRenderer.camera.viewportWidth * WorldRenderer.camera.zoom;
                float effectiveViewportHeight = WorldRenderer.camera.viewportHeight * WorldRenderer.camera.zoom;

                WorldRenderer.camera.zoom = MathUtils.clamp( WorldRenderer.camera.zoom, 0.05f, Constants.VIEWPORT_WIDTH /  WorldRenderer.camera.viewportWidth);
                WorldRenderer.camera.position.x = MathUtils.clamp( WorldRenderer.camera.position.x, effectiveViewportWidth / 2f, Constants.VIEWPORT_WIDTH - effectiveViewportWidth / 2f);
                WorldRenderer.camera.position.y = MathUtils.clamp( WorldRenderer.camera.position.y, effectiveViewportHeight / 2f, Constants.VIEWPORT_HEIGHT - effectiveViewportHeight / 2f);
                WorldRenderer.camera.update();
                continue;
            }
        }*/


        currentPlayer = player;
        lastActions = actions;
        updateActionPanel(actions);
        updateCardPanel(player.getCityCards());
        updateDiseasePanel(currentPlayer.getCity().getDiseases());
        updatePlayerPanel(new ArrayList<Player>());
    }

    private void addAcceptCancelButtons() {
        List<Action> acceptActions = new ArrayList<>();
        acceptActions.add(new AcceptAction());
        acceptActions.add(new CancelAction());
        updateActionPanel(acceptActions);
        updateDiseasePanel(currentPlayer.getCity().getDiseases());

    }

    protected void updateActionPanel(List<Action> actions) {
        ServiceLocator.getWorldRenderer().setPlayerActions(actions);
    }

    protected void updateCardPanel(List<CityCard> cityCards) {
        updateCardPanel(cityCards, false, 1);
    }

    protected void updateCardPanel(List<CityCard> cityCards, boolean isMulti, int maxSelected) {
        ServiceLocator.getWorldRenderer().showCardDeck(false, isMulti, maxSelected);
        ServiceLocator.getWorldRenderer().setPlayerCards(cityCards);
    }

    protected void updateDiseasePanel(List<Disease> diseases) {
        ServiceLocator.getWorldRenderer().showDiseaseDeck(false);
        ServiceLocator.getWorldRenderer().setCityDisease(diseases);
    }

    protected void updatePlayerPanel(List<Player> players) {
        ServiceLocator.getWorldRenderer().showPlayerDeck(false);
        ServiceLocator.getWorldRenderer().setPlayers(players);
    }

    @Override
    public void initiateBreakout(List<City> iCities) {
    }

    public Player getCurrentPlayer() {
        return currentPlayer;
    }

    public String getTurnCounter() {
        return turnCounter + ";" + turnCounterAll;
    }

    public boolean canSelectCities() {
        return lastSelectedAction != null;
    }
}
